package com.wongoing.sys.action;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.wongoing.base.Json;
import com.wongoing.base.PageResult;
import com.wongoing.sys.model.SysPermission;
import com.wongoing.sys.model.SysPost;
import com.wongoing.sys.model.SysUser;
import com.wongoing.sys.model.ext.SysUserExt;
import com.wongoing.sys.service.SysPermissionService;
import com.wongoing.sys.service.SysPostService;
import com.wongoing.sys.service.SysUserService;
import com.wongoing.sys.shiro.ShiroHelper;
import com.wongoing.sys.shiro.ShiroUser;
import com.wongoing.sys.shiro.ShiroUserTypeUsernamePasswordToken;
import com.wongoing.sys.util.Constants;
import com.wongoing.sys.viewmodel.JsonResult;
import com.wongoing.util.LogService;
import com.wongoing.util.LoginType;
import com.wongoing.util.ModelAndViewConstants;
import com.wongoing.util.PageUtil;
import com.wongoing.util.Status;
import com.wongoing.util.SubjectUtil;

@Controller
@RequestMapping("/sys/sysUserAction")
public class SysUserAction extends BaseAction{
	
	private static final String USER_LOGIN_TYPE = LoginType.USER.toString();
	
	private SysUserService service;
	private SysPermissionService sysPermissionService;
	private SysPostService sysPostService;

	@Autowired
	public void setService(SysUserService service) {
		this.service = service;
	}
	@Autowired
	public void setSysPermissionService(SysPermissionService sysPermissionService) {
		this.sysPermissionService = sysPermissionService;
	}
	@Autowired
	public void setSysPostService(SysPostService sysPostService) {
		this.sysPostService = sysPostService;
	}
	
	
	/**
	 * 功能说明：Ajax登录请求处理方法，以json对象方式返回至客户端
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:03:12
	 * @param userName 用户账号
	 * @param password 用户密码
	 * @param captcha 验证码
	 * @param rememberMe 是否记住我
	 * @param session HttpSession对象
	 * @return 返回json对象
	 */
	@ResponseBody
	@RequestMapping("/login")
	public Json login(String userName, String password, String captcha, boolean rememberMe, HttpSession session) {
		Json jsonResult = new Json();
		jsonResult.setTitle("登录提示");
		try {
			String sessionCaptcha = (String)session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);	//获取Session中验证码的值
			LogService.getInstance(this).debug("sessionCaptcha = " + sessionCaptcha);
			if (captcha.equals(sessionCaptcha)) {
				Subject subject = SecurityUtils.getSubject();
				if(subject.isAuthenticated()) {
					subject.logout();//先退出
				}
				ShiroUserTypeUsernamePasswordToken token = new ShiroUserTypeUsernamePasswordToken(userName,password,USER_LOGIN_TYPE);
				token.setRememberMe(false);
				try {
					subject.login(token);
					LogService.getInstance(this).info("当前用户=" + subject.getPrincipal());
					LogService.getInstance(this).debug("sessionTimeout====>" + subject.getSession().getTimeout());
					jsonResult.setStatus(true);
				}
				catch(UnknownSessionException use) {
					subject = new Subject.Builder().buildSubject();
					subject.login(token);
					LogService.getInstance(this).error(Status.UNKNOWN_SESSION_EXCEPTION.toString());
					jsonResult.setMessage(Status.UNKNOWN_SESSION_EXCEPTION.toString());
				}
				catch(UnknownAccountException uae) {
					LogService.getInstance(this).error(Status.UNKNOWN_ACCOUNT_EXCEPTION.toString());
					jsonResult.setMessage(Constants.UNKNOWN_ACCOUNT_EXCEPTION);
				}
				catch(IncorrectCredentialsException ice) {
					jsonResult.setMessage(Constants.INCORRECT_CREDENTIALS_EXCEPTION);
				}
				catch(LockedAccountException lae) {
					jsonResult.setMessage(Constants.LOCKED_ACCOUNT_EXCEPTION);
				}
				catch(AuthenticationException ae) {
					jsonResult.setMessage(Constants.AUTHENTICATION_EXCEPTION);
				}
			}
			else {
				LogService.getInstance(this).warn(Constants.INCORRECT_CAPTCHA_EXCEPTION);
				jsonResult.setMessage(Constants.INCORRECT_CAPTCHA_EXCEPTION);
			}
		}
		catch(Exception e) {
			LogService.getInstance(this).error(e.getMessage(), e.getCause());
			jsonResult.setMessage(Constants.UNKNOWN_EXCEPTION);
		}
		return jsonResult;
	}
	
	
	/**
	 * 功能说明：注销请求方法，以json对象方式返回至客户端
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:03:12
	 * @return 返回ModelAndView视图对象
	 */
	@RequestMapping("/logout")
	public ModelAndView logout() {
		ModelAndView mv = null;
		try
		{
			Subject subject = SecurityUtils.getSubject();
			subject.logout();
			LogService.getInstance(this).debug("注销成功!");
			mv = new ModelAndView("redirect:/login.jsp");
		}
		catch(Exception ex) {
			LogService.getInstance(this).debug("注销失败：" + ex.getMessage());
			mv = new ModelAndView("redirect:/error.jsp");
		}
		return mv;
	}
	
	/**
	 * 功能说明：Ajax方式获取当前用户系统菜单
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:03:12
	 * @return 返回json对象，包含菜单数据
	 */
	@ResponseBody
	@RequestMapping(value="/getSystemMenus", method=RequestMethod.GET )
	public Json<List<SysPermission>> getSystemMenus() {
		Json<List<SysPermission>> jsonResult = new Json<List<SysPermission>>();
		jsonResult.setTitle("获取系统菜单提示");
		try
		{
			Subject subject = SecurityUtils.getSubject();
			String username = subject.getPrincipal().toString();
			List<SysPermission> perList = null;
			if (Constants.SYSTEM_ADMINISTRATOR.equals(username)) {
				perList = this.sysPermissionService.getByStatusAndType(Constants.PERSISTENCE_ENABLE_STATUS, "F"); 
			}
			else {
				perList = this.sysPermissionService.getByUserAccount(username, Constants.PERSISTENCE_ENABLE_STATUS, "F");
			}
			jsonResult.setMessage("获取系统菜单成功!");
			jsonResult.setData(perList);
			jsonResult.setStatus(true);
			LogService.getInstance(this).debug("获取系统菜单成功!");
		}
		catch(Exception ex) {
			LogService.getInstance(this).error("获取系统菜单失败：" + ex.getMessage(), ex);
			jsonResult.setMessage("获取系统菜单失败:" + ex.getMessage());
		}
		return jsonResult;
	}
	
	/**
	 * 功能说明：进入列表操作，分页数据显示
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:03:12
	 * @param pageSize 每页记录数
	 * @param pageCurrent 当前页索引
	 * @param orderField 排序字段
	 * @param orderDirection 排序方向
	 * @param paramField 参数字段
	 * @param paramValue 参数值
	 * @return 返回json对象
	 */
	@RequestMapping(value="/toList")
	public ModelAndView toList(Integer pageSize, Integer pageCurrent, String orderField, String orderDirection,
			String paramAccount, String paramName, String paramTel,String paramEmail) {
		ModelAndView mv = null;
		try {
			
			PageResult<SysUserExt> pageResult = PageUtil.pageSet(this.getClass(), pageSize, pageCurrent, orderField, orderDirection);
			pageResult.getParam().put("status", "0");
			//模糊查询判断
			List<Boolean> multiFuzzyQuery = new ArrayList<Boolean>();
			if (paramEmail != null && !"".equals(paramEmail)) {
				pageResult.getParam().put("email", paramEmail);
				pageResult.setOrderField("su.Email");
				pageResult.setOrderDirection("DESC");
				pageResult.getExt().put("paramEmail", paramEmail);
				multiFuzzyQuery.add(true);
			}else{
				multiFuzzyQuery.add(false);
			}
			if (paramTel != null && !"".equals(paramTel)) {
				pageResult.getParam().put("telephone", paramTel);
				pageResult.setOrderField("su.Telephone");
				pageResult.setOrderDirection("DESC");
				pageResult.getExt().put("paramTel", paramTel);
				multiFuzzyQuery.add(true);
			}else{
				multiFuzzyQuery.add(false);
			}
			
			if (paramName != null && !"".equals(paramName)) {
				pageResult.getParam().put("name", paramName);
				pageResult.setOrderField("su.Name");
				pageResult.setOrderDirection("DESC");
				pageResult.getExt().put("paramName", paramName);
				multiFuzzyQuery.add(true);
			}else{
				multiFuzzyQuery.add(false);
			}
			if (paramAccount != null && !"".equals(paramAccount)) {
				pageResult.getParam().put("account", paramAccount);
				pageResult.setOrderField("su.Account");
				pageResult.setOrderDirection("DESC");
				pageResult.getExt().put("paramAccount", paramAccount);
				multiFuzzyQuery.add(true);
			}else{
				multiFuzzyQuery.add(false);
			}
			if(PageUtil.multiFuzzyQuery(multiFuzzyQuery)){
				pageResult.setOrderField("su.Id");
				pageResult.setOrderDirection("ASC");
			}
			pageResult = this.service.getUserListPageResult(pageResult);
			
			//处理密码显示为******
			for(SysUserExt user : pageResult.getList()) {
				user.setPassword("******");
			}
			
			mv = new ModelAndView();
			mv.addObject(ModelAndViewConstants.PAGE_RESULT, pageResult);
			mv.setViewName(ModelAndViewConstants.USER_MAIN_VIEW);
			LogService.getInstance(this).debug("获取用户分页数据成功："+ModelAndViewConstants.USER_MAIN_VIEW);
		}
		catch(Exception ex) {
			LogService.getInstance(this).error("分页获取用户列表失败：" + ex.getMessage(), ex);
			mv = new ModelAndView(ModelAndViewConstants.ERROR_VIEW);
		}
		return mv;
	}
	
	/**
	 * 功能说明：执行账户验证操作
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:04:30
	 * @param op
	 * @param account
	 * @param original
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value="/doAccountValidate")
	public Map<String,Object> doAccountValidate(String op, String account, String original){
		Map<String,Object> jsonResult = null;
		try {
			String where = " BINARY Account='"+account+"' and Status='0' ";
			List<SysUser> list = this.service.getByWhere(where);
			if(list!=null){
				Integer count = list.size();
				switch (count) {
				case 0:
					jsonResult = JsonResult.jsonValidateReturn(true, "验证通过，该帐号可以使用");
					LogService.getInstance(this).debug("帐号验证通过，可使用");
					break;
				case 1:
					if(ModelAndViewConstants.OPERATION_VALUE_EDIT.equals(op)){
						if(account.equals(original)){
							jsonResult = JsonResult.jsonValidateReturn(true, "验证通过，该帐号可以使用");
							LogService.getInstance(this).debug("帐号名验证通过，可使用");
						}else{
							jsonResult = JsonResult.jsonValidateReturn(false, "该帐号已被使用");
							LogService.getInstance(this).debug("帐号已被使用，不可使用");
						}
					}else{
						jsonResult = JsonResult.jsonValidateReturn(false, "该帐号称已被使用");
						LogService.getInstance(this).debug("帐号称已被使用，不可使用");
					}
					break;
				default:
					jsonResult = JsonResult.jsonValidateReturn(false, "该帐号已被使用");
					LogService.getInstance(this).debug("帐号已被使用，不可使用");
					break;
				}
			}else{
				jsonResult = JsonResult.jsonValidateReturn(false, "验证失败");
				LogService.getInstance(this).error("帐号验证失败");
			}
		} catch (Exception e) {
			jsonResult = JsonResult.jsonValidateReturn(false, "验证失败");
			LogService.getInstance(this).error("帐号验证失败");
		}
		return jsonResult;
	}
	
	/**
	 * 功能说明：进入添加界面
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:05:28
	 * @return
	 */
	@RequestMapping(value="/toAdd")
	public ModelAndView toAdd(){
		ModelAndView mv = null;
		try {
			Map<String,Object> param = new HashMap<String, Object>();
			param.put("status", "0");
			List<SysPost> post = this.sysPostService.getByParam(param);
			mv = new ModelAndView();
			mv.addObject(ModelAndViewConstants.OPERATION_KEY,ModelAndViewConstants.OPERATION_VALUE_ADD);
			mv.addObject(ModelAndViewConstants.TITLE_KEY, "添加用户");
			mv.addObject(ModelAndViewConstants.POST_MODEL, post);
			mv.setViewName(ModelAndViewConstants.USER_EDIT_VIEW);
			LogService.getInstance(this).error("进入用户添加功能成功：" +ModelAndViewConstants.USER_EDIT_VIEW);
		}
		catch(Exception ex) {
			LogService.getInstance(this).error("进入用户添加失败：" + ex.getMessage(), ex);
			mv = new ModelAndView("redirect:/error.jsp");
		}
		return mv;
	}
	
	/**
	 * 功能说明：进入编辑操作
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:05:53
	 * @param id 用户id，主键值
	 * @return
	 */
	@RequestMapping(value="/toEdit")
	public ModelAndView toEdit(Integer id) {
		ModelAndView mv = null;
		try {
			SysUser user = this.service.getByPrimaryKey(id);
			//处理密码
			if (user != null) {
				user.setPassword("******");
			}
			Map<String,Object> param = new HashMap<String, Object>();
			param.put("status", "0");
			List<SysPost> post = this.sysPostService.getByParam(param);
			mv = new ModelAndView();
			mv.addObject(ModelAndViewConstants.OPERATION_KEY,ModelAndViewConstants.OPERATION_VALUE_EDIT);
			mv.addObject(ModelAndViewConstants.TITLE_KEY, "添加用户");
			mv.addObject(ModelAndViewConstants.USER_MODEL, user);
			mv.addObject(ModelAndViewConstants.POST_MODEL, post);
			mv.setViewName(ModelAndViewConstants.USER_EDIT_VIEW);
		}
		catch(Exception ex) {
			LogService.getInstance(this).error("进入用户编辑失败：" + ex.getMessage(), ex);
			mv = new ModelAndView(ModelAndViewConstants.ERROR_VIEW);
		}
		return mv;
	}
	
	/**
	 * 功能说明：执行保存操作
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:05:53
	 * @param entity 用户信息实体
	 * @param op op=add为添加操作，op=edit为编辑操作
	 * @return 返回json对象
	 */
	@ResponseBody
	@RequestMapping(value="/doSave")
	public Map<String, Object> doSave(SysUser entity, String op) {
		Map<String, Object> jsonResult = null;
		try {
			String tabid = tabid(ModelAndViewConstants.USER_SYS_ID);
			Date now = new Date();				
			Subject subject = SecurityUtils.getSubject();
			ShiroUser currUser = (ShiroUser)subject.getPrincipal();
			if (null == op || ModelAndViewConstants.OPERATION_VALUE_ADD.equals(op)) {
				entity.setCreateDate(now);
				entity.setFirstVisit(now);
				entity.setModifyDate(now);
				entity.setLastVisit(now);
				if (currUser != null) {
					entity.setCreateUser(currUser.getUserId());
				}
				
				entity.setStatus("0");
				//密码加密
				entity.setPassword(ShiroHelper.sha1Encrypt(entity.getPassword(), entity.getAccount(), ShiroHelper.SALT2, ShiroHelper.HASHITERATIONS));
				
				int count = this.service.insert(entity);
				if (count > 0) {
					LogService.getInstance(this).debug("添加用户成功!");
				}
			}
			else {
				if (currUser != null) {
					entity.setModifyUser(currUser.getUserId());
				}
				entity.setModifyDate(now);
				//密码修改
				Map<String, Object> param = new HashMap<String, Object>();
				param.put("account", entity.getAccount());
				List<SysUser> users = this.service.getByParam(param);
				if (null != users && !users.isEmpty()) {
					if (null != entity.getPassword() && entity.getPassword().equals("******")) {
						entity.setPassword(users.get(0).getPassword());
					}
					else if (null != entity.getPassword()) {
						entity.setPassword(ShiroHelper.sha1Encrypt(entity.getPassword(), entity.getAccount(), ShiroHelper.SALT2, ShiroHelper.HASHITERATIONS));
					}
				}
				//更新
				int count = this.service.updateByPrimaryKey(entity); 
				if (count > 0) {
					LogService.getInstance(this).debug("编辑用户成功!");
				}
			}
			Integer statusCode = 200;
			String msg = "用户信息保存成功";
			jsonResult = JsonResult.jsonReturn(statusCode, msg, tabid);
		}
		catch(Exception ex) {
			LogService.getInstance(this).error("保存用户失败：" + ex.getMessage(), ex);
			String msg =  "保存用户失败：" + ex.getMessage();
			jsonResult = JsonResult.jsonReturnErr(msg);
		}
		return jsonResult;
	}
	
	/**
	 * 功能说明：执行删除操作
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:05:53
	 * @param id 用户id，主键值
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value="/doDel")
	public Map<String, Object> doDel(Integer id) {
		Map<String, Object> result = null;
		try {
			SysUser entity = new SysUser();
			entity.setId(id);
			entity.setStatus("1");
			int count = this.service.updateByPrimaryKey(entity);
			if (count > 0) {
				LogService.getInstance(this).debug("删除用户成功!");
			}
			Integer statusCode = 200;
			String msg = "删除成功!";
			String tabid = tabid(ModelAndViewConstants.USER_SYS_ID);
			result = JsonResult.jsonReturn(Status.OK.getCode(), msg, tabid,false,"","");
		}
		catch(Exception ex) {
			LogService.getInstance(this).error("删除用户[" + id + "]失败：" + ex.getMessage(), ex);
			String msg =  "删除用户[" + id + "]失败：" + ex.getMessage();
			result = JsonResult.jsonReturnErr(msg);
		}
		return result;
	}
	
	/**
	 * 功能说明：执行修改密码操作
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017年10月15日 下午1:05:53
	 * @param id 用户id，主键值
	 * @param account 用户账户
	 * @param password 用户密码
	 * @param newpassword 新密码
	 * @return 返回json对象
	 */
	@ResponseBody
	@RequestMapping(value="/doChangePwd")
	public Map<String, Object> doChangePwd(Integer id, String account, String password, String newpassword) {
		Map<String, Object> result = new HashMap<String, Object>();
		try {
			SysUser user = this.service.getByPrimaryKey(id);
			if (user == null) {
				String msg = "用户不存在，可能会话过期，请重新登录系统尝试!";
				result = JsonResult.jsonReturnErr(msg);
			}
			else if (!user.getPassword().equals(ShiroHelper.sha1Encrypt(password, account, ShiroHelper.SALT2, ShiroHelper.HASHITERATIONS))) {
				String msg = "旧密码输入不正确，请重新输入旧密码尝试!";
				result = JsonResult.jsonReturnErr(msg);
			}
			else {
				user.setPassword(ShiroHelper.sha1Encrypt(newpassword, account, ShiroHelper.SALT2, ShiroHelper.HASHITERATIONS));
				int count = this.service.updateByPrimaryKey(user);
				if (count == 0)
				{
					LogService.getInstance(this).warn("密码没有修改成功!");
				}
				Integer status = 200;
				String msg = "修改成功！";
				String tabid = tabid(ModelAndViewConstants.USER_SYS_ID);
				result = JsonResult.jsonReturn(status.intValue(), msg, tabid);
			}
		}
		catch(Exception ex) {
			LogService.getInstance(this).error("用户[" + account + "]修改密码失败：" + ex.getMessage(), ex);
			result = JsonResult.jsonReturnErr("用户[" + account + "]修改密码失败：" + ex.getMessage());
		}
		return result;
	}
}
